package johnkkk.com.system_k;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.opengl.GLES32;
import android.opengl.Matrix;
import android.os.Build;
import android.support.annotation.RequiresApi;

import com.graphics.GLGraphics;
import com.graphics.element.AbsSceneNode;
import com.math3d.MatrixUtil;
import com.math3d.Vector4fv;
import com.system.FileUtils;
import com.system.GLLog;
import com.system.Shader;
import com.tools.BitmapTools;
import com.tools.GLBufferTools;
import com.tools.SizeOf;
import com.tools.TextureTools;

import java.io.File;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.microedition.khronos.opengles.GL;

/**
 * @Author: clm
 * @Date: 2018-11-01
 * 地形系统
 */

public class Terrain extends AbsSceneNode{
    //静态纹理生成
    public final static int S_TEXTURE_MODE_STATIC = 0x001;
    //实时纹理计算
    public final static int S_TEXTURE_MODE_REAL_TIME = 0x002;
    //纹理缩放尺度
    private float vt, ut;               //用于缩放纹理坐标(当vt=1时,纹理坐标v规范在[0,1]之间,当vt等于w时,纹理坐标规范到[0,w]之间,同理u的规范
    private float vt2, ut2;             //用于细节纹理隐射(只有当模式是S_TEXTURE_MODE_STATIC时才有)
    //地形网格宽度
    private int mTerrainWidth;
    //地形网格高度
    private int mTerrainHeight;
    //地形网格边长
    private int mRectLength;
    //网格边长倒数(用于计算地形高度)
    private float mRectLengthSqrt;
    //VAO
    private int[] mTerrainVAO;
    //索引数量(三角形模式)
    private int mIndexSize;
    //高度缩放值
    private float mScaleHeight = 0.1f;
    //shader
    private Shader mShader;
    private Shader mLineShader;
    //模型矩阵
    private float[] mM_matrix;
    //线框模式vao
    private int[] mLineVAO;
    //线框模式索引数量
    private int mLineIndexCount;
    //最大高度值(用于计算管辖区域)
    private int mMax_Height;
    //地形纹理
    private Bitmap mTerrainBitmap;
    //地形id
    private int mTerrainTextureID[];
    //纹理模式(动态纹理映射,静态纹理映射)
    private int mTextureMapMode;
    //地形位置
    private float[] mLocation = {0.0f, 0.0f, 0.0f};
    //索引数据
    public int indexs[];
    //顶点数据
    public float vertexsFloatArray[];
    //uv数据
    public float uvs[];
    public float uvs2[];
    //地形原数据
    private TerrainVertex3D terrainArray[][];

    public Bitmap getTerrainBitmap() {
        return mTerrainBitmap;
    }

    /**
     * 用于生成地形网格的中间网格顶点结构
     */
    public static class TerrainVertex3D{

        float x, y, z;

        @Override
        public String toString() {
            return "TerrainVertex3D [x=" + x + ", y=" + y + ", z=" + z + "]";
        }

    }

    public int getmTerrainWidth() {
        return mTerrainWidth;
    }

    public void setmTerrainWidth(int mTerrainWidth) {
        this.mTerrainWidth = mTerrainWidth;
    }

    public int getmTerrainHeight() {
        return mTerrainHeight;
    }

    public void setmTerrainHeight(int mTerrainHeight) {
        this.mTerrainHeight = mTerrainHeight;
    }

    /**
     * 获取地形缩放宽度
     * @return
     */
    public float getWidth(){
        return mTerrainWidth * mRectLength;
    }

    /**
     * 获取地形缩放高度
     * @return
     */
    public float getHeight(){
        return mTerrainHeight * mRectLength;
    }
    /**
     * 加载高度信息
     * @return
     */
    public final int[] getHMap(){
        mMax_Height = Integer.MIN_VALUE;
        Bitmap hmap = FileUtils.getFromAssetsAtBitmap("hmap/hieght_map_min.png");
        int x = hmap.getWidth();
        int y = hmap.getHeight();
        mTerrainWidth = x - 1;
        mTerrainHeight = y - 1;
        int pixels[] = new int[x * y];
        hmap.getPixels(pixels, 0, x, 0, 0, x, y);
        int hm[] = new int[x * y];
        for(int i = 0;i < pixels.length;i++){
            int clr = pixels[i];
            int red = (clr & 0x00ff0000) >> 16; // 取高两位
            hm[i] = red;
            mMax_Height = Math.max(mMax_Height, hm[i]);
            //GLLog.loge("r:" + red);
        }
        return hm;
    }
    /**
     * 根据索引三角形生成线框模式渲染的vao
     * @param indexs
     * @param vertexs
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public final void markLineVAO(int indexs[], float vertexs[]){
        ArrayList<Integer> lineIndexs = new ArrayList<>();
        for(int i = 0;i < indexs.length;i+=3){
            //取一个三角形索引出来
            int id0 = indexs[i];
            int id1 = indexs[i + 1];
            int id2 = indexs[i + 2];
            //生成3对索引
            lineIndexs.add(id0);
            lineIndexs.add(id1);
            lineIndexs.add(id1);
            lineIndexs.add(id2);
            lineIndexs.add(id2);
            lineIndexs.add(id0);
        }
        int lineIndexsI[] = new int[lineIndexs.size()];
        mLineIndexCount = lineIndexs.size();
        for(int i = 0;i < lineIndexs.size();i++){
            lineIndexsI[i] = lineIndexs.get(i);
        }
        mLineVAO = new int[1];
        int vbo[] = new int[1];
        GLES32.glGenBuffers(1, vbo, 0);
        GLES32.glGenVertexArrays(1, mLineVAO, 0);
        GLES32.glBindVertexArray(mLineVAO[0]);
        GLES32.glBindBuffer(GLES32.GL_ARRAY_BUFFER, vbo[0]);
        FloatBuffer fb = GLBufferTools.getFloatBuffer(vertexs);
        GLES32.glBufferData(GLES32.GL_ARRAY_BUFFER, fb.limit() * 4, fb, GLES32.GL_STATIC_DRAW);
        GLES32.glVertexAttribPointer(0x001, 3, GLES32.GL_FLOAT, false, 3 * SizeOf.S_FLOAT_SIZE, 0);
        GLES32.glEnableVertexAttribArray(0x001);
        GLES32.glBindBuffer(GLES32.GL_ARRAY_BUFFER, 0);
        int ebo[] = new int[1];
        GLES32.glGenBuffers(1, ebo, 0);
        GLES32.glBindBuffer(GLES32.GL_ELEMENT_ARRAY_BUFFER, ebo[0]);
        IntBuffer ib = GLBufferTools.getIntBuffer(lineIndexsI);
        GLES32.glBufferData(GLES32.GL_ELEMENT_ARRAY_BUFFER, ib.limit() * 4, ib, GLES32.GL_STATIC_DRAW);
        GLES32.glBindVertexArray(0);
        GLES32.glBindBuffer(GLES32.GL_ELEMENT_ARRAY_BUFFER, 0);
        mLineShader = new Shader("line_vs.glsl", "line_fs.glsl");
        GLES32.glUseProgram(mLineShader.mShaderProgram);
        MatrixUtil.normalize(mM_matrix);
        Matrix.translateM(mM_matrix, 0, 0, 0.1f, 0.0f);
        GLES32.glUniformMatrix4fv(GLES32.glGetUniformLocation(mLineShader.mShaderProgram, "m_matrix"), 1, false, GLBufferTools.getFloatBuffer(mM_matrix));
        GLES32.glUseProgram(0);
    }

    /**
     * 生成地形
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public final void markTerrain(){
        int hm[] = getHMap();
        //顶点数据
        //生成4*4网格(总共有5*5个顶点
        mRectLength = 5;//假设每个网格边长为10
        mRectLengthSqrt = 1.0f / mRectLength;
        int hi = 0;
        terrainArray = new TerrainVertex3D[mTerrainWidth + 1][mTerrainHeight + 1];
        for(int z = 0;z < terrainArray.length;z++){
            for(int x = 0;x < terrainArray[z].length;x++){
                terrainArray[x][z] = new TerrainVertex3D();
                terrainArray[x][z].x = z * mRectLength;
                terrainArray[x][z].y = hm[hi] * mScaleHeight;
                terrainArray[x][z].z = x * mRectLength;
                hi++;
            }
        }
        Vector4fv vertexs[] = new Vector4fv[(mTerrainWidth + 1) * (mTerrainHeight + 1)];                   //用于描述顶点结构
        vertexsFloatArray = new float[(mTerrainWidth + 1) * (mTerrainHeight + 1) * 3];         //用于构建vao
        uvs = new float[(mTerrainWidth + 1) * (mTerrainHeight + 1) * 2];
        uvs2 = new float[(mTerrainWidth + 1) * (mTerrainHeight + 1) * 2];               //只有是静态模式时才有这组纹理坐标(用于实现细节纹理)
        int uvIndex = 0;
        int index = 0;
        int floatIndex = 0;
        mM_matrix = new float[16];
        MatrixUtil.normalize(mM_matrix);
        Matrix.translateM(mM_matrix, 0, mLocation[0], mLocation[1], mLocation[2]);
        Vector4fv result;
        if(mTextureMapMode == S_TEXTURE_MODE_STATIC){
            vt = 1;
            ut = 1;
            vt2 = (mTerrainHeight + 1) * 0.5f;
            ut2 = (mTerrainWidth + 1) * 0.5f;
        }else{
            vt = (mTerrainHeight + 1) * 0.5f;
            ut = (mTerrainWidth + 1) * 0.5f;
        }
        float k1 = -(1.0f * vt) / (mTerrainHeight + 1);
        float k2 = (1.0f * ut) / (mTerrainWidth + 1);
        float k11 = -(1.0f * vt2) / (mTerrainHeight + 1);
        float k22 = (1.0f * ut2) / (mTerrainWidth + 1);
        float u, v;
        float u2, v2;
        for(int z = 0;z < terrainArray.length;z++) {
            for (int x = 0; x < terrainArray[z].length; x++) {
                result = new Vector4fv();
                vertexs[index] = new Vector4fv();
                vertexs[index].getVec()[0] = terrainArray[x][z].x;
                vertexs[index].getVec()[1] = terrainArray[x][z].y;
                vertexs[index].getVec()[2] = terrainArray[x][z].z;
                vertexs[index].getVec()[3] = 1.0f;
                //提前进行模型变换
                Matrix.multiplyMV(result.getVec(), 0, mM_matrix, 0, vertexs[index].getVec(), 0);
                vertexsFloatArray[floatIndex++] = result.getVec()[0];
                vertexsFloatArray[floatIndex++] = result.getVec()[1];
                vertexsFloatArray[floatIndex++] = result.getVec()[2];
                index++;
                //v = -1/height * z + 1;
                //u = 1/width * x;
                v = k1 * z + vt;
                u = k2 * x;
                uvs[uvIndex] = u;
                uvs[uvIndex + 1] = v;
                //如果是静态纹理隐射
                if(S_TEXTURE_MODE_STATIC == mTextureMapMode){
                    v2 = k11 * z + vt2;
                    u2 = k22 * x;
                    uvs2[uvIndex] = u2;
                    uvs2[uvIndex + 1] = v2;
                }
                uvIndex+=2;
            }
        }
        //索引数据
        int indexs[] = new int[mTerrainWidth * mTerrainHeight * 6];
        mIndexSize = indexs.length;
        for(int i = 0,line = 0,rect = 0;i < indexs.length;line += 1,rect+=1){
            //每个网格6个索引
            if(rect != 0 && rect % mTerrainWidth == 0){
                line+=1;
            }
            indexs[i] = line + mTerrainWidth + 2;		//当前网格下一行的第二个
//            indexs[i] = line + 0;				//当前网格第一行的第一个
            indexs[i + 1] = line + mTerrainWidth + 1;		//当前网格下一行的第一个
//            indexs[i + 2] = line + mTerrainWidth + 2;		//当前网格下一行的第二个
            indexs[i + 2] = line + 0;				//当前网格第一行的第一个
            indexs[i + 3] = line + 0;			//当前网格第一行的第一个
//            indexs[i + 3] = line + mTerrainWidth + 2;		//当前网格下一行的第二个
            indexs[i + 4] = line + 1;			//当前网格第一行的第二个
//            indexs[i + 5] = line + 0;			//当前网格第一行的第一个
            indexs[i + 5] = line + mTerrainWidth + 2;		//当前网格下一行的第二个
            i += 6;
        }
        //生成vao
        mTerrainVAO = new int[1];
        int vbo[] = new int[1];
        GLES32.glGenVertexArrays(1, mTerrainVAO, 0);
        GLES32.glGenBuffers(1, vbo, 0);
        GLES32.glBindVertexArray(mTerrainVAO[0]);
        GLES32.glBindBuffer(GLES32.GL_ARRAY_BUFFER, vbo[0]);
        FloatBuffer fb = GLBufferTools.getFloatBuffer(vertexsFloatArray);
        FloatBuffer uvFb = GLBufferTools.getFloatBuffer(uvs);
        FloatBuffer uvFb2 = GLBufferTools.getFloatBuffer(uvs2);
        if(S_TEXTURE_MODE_STATIC == mTextureMapMode){
            GLES32.glBufferData(GLES32.GL_ARRAY_BUFFER, (fb.limit() + uvFb.limit() + uvFb2.limit()) * 4, null, GLES32.GL_STATIC_DRAW);
        }
        else{
            GLES32.glBufferData(GLES32.GL_ARRAY_BUFFER, (fb.limit() + uvFb.limit()) * 4, null, GLES32.GL_STATIC_DRAW);
        }
        GLES32.glBufferSubData(GLES32.GL_ARRAY_BUFFER, 0, fb.limit() * 4, fb);
        GLES32.glBufferSubData(GLES32.GL_ARRAY_BUFFER, fb.limit() * 4, uvFb.limit() * 4, uvFb);
        GLES32.glVertexAttribPointer(0x001, 3, GLES32.GL_FLOAT, false, 3 * SizeOf.S_FLOAT_SIZE, 0);
        GLES32.glEnableVertexAttribArray(0x001);
        GLES32.glVertexAttribPointer(0x002, 2, GLES32.GL_FLOAT, false, 2 * SizeOf.S_FLOAT_SIZE, fb.limit() * 4);
        GLES32.glEnableVertexAttribArray(0x002);
        if(S_TEXTURE_MODE_STATIC == mTextureMapMode){
            GLES32.glBufferSubData(GLES32.GL_ARRAY_BUFFER, (fb.limit() + uvFb.limit()) * 4, uvFb2.limit() * 4, uvFb2);
            GLES32.glVertexAttribPointer(0x003, 2, GLES32.GL_FLOAT, false, 2 * SizeOf.S_FLOAT_SIZE, (fb.limit() + uvFb.limit()) * 4);
            GLES32.glEnableVertexAttribArray(0x003);
        }
        GLES32.glBindBuffer(GLES32.GL_ARRAY_BUFFER, 0);
        int ebo[] = new int[1];
        GLES32.glGenBuffers(1, ebo, 0);
        GLES32.glBindBuffer(GLES32.GL_ELEMENT_ARRAY_BUFFER, ebo[0]);
        IntBuffer ib = GLBufferTools.getIntBuffer(indexs);
        GLES32.glBufferData(GLES32.GL_ELEMENT_ARRAY_BUFFER, ib.limit() * 4, ib, GLES32.GL_STATIC_DRAW);
        GLES32.glBindVertexArray(0);
        GLES32.glBindBuffer(GLES32.GL_ELEMENT_ARRAY_BUFFER, 0);
        //构建线框模式vao
        markLineVAO(indexs, vertexsFloatArray);
        //生成地形纹理
        if(mTextureMapMode == S_TEXTURE_MODE_STATIC){            //静态纹理映射
            //shader
            mShader = new Shader("terrain_vs.glsl", "terrain_fs.glsl");
            mTerrainBitmap = markTexture(hm);
            mTerrainTextureID = new int[2];
            mTerrainTextureID[0] = TextureTools.genSimplerTextureAtBitmap(GLES32.GL_TEXTURE_2D, mTerrainBitmap)[0];
            mTerrainTextureID[1] = TextureTools.genSimplerTextureAtWrapRepeat(GLES32.GL_TEXTURE_2D, "textures/terrain_hint.png");
            GLES32.glUseProgram(mShader.mShaderProgram);
            GLES32.glUniform1i(GLES32.glGetUniformLocation(mShader.mShaderProgram, "tex0"), 0);
            GLES32.glUniform1i(GLES32.glGetUniformLocation(mShader.mShaderProgram, "tex1"), 1);
            GLES32.glUseProgram(0);
        }
        else{
            //shader
            mShader = new Shader("terrain_vs2.glsl", "terrain_fs2.glsl");
            mTerrainTextureID = new int[4];                            //4张纹理(暂时默认)
            mTerrainTextureID[0] = TextureTools.genSimplerTextureAtWrapRepeat(GLES32.GL_TEXTURE_2D, "textures/loess.png");
            mTerrainTextureID[1] = TextureTools.genSimplerTextureAtWrapRepeat(GLES32.GL_TEXTURE_2D, "textures/grassland.png");
            mTerrainTextureID[2] = TextureTools.genSimplerTextureAtWrapRepeat(GLES32.GL_TEXTURE_2D, "textures/rock.png");
            mTerrainTextureID[3] = TextureTools.genSimplerTextureAtWrapRepeat(GLES32.GL_TEXTURE_2D, "textures/snow.png");
            float t = ((mMax_Height * mScaleHeight) / (mTerrainTextureID.length));          //这里让t分配刚好最高点的高度值为最后一个纹理100%可视度位置点
            GLES32.glUseProgram(mShader.mShaderProgram);
            String[] textures = {"loess","grassland","rock","snow"};
            float offsetX = -0.1f;          //这个变量的作用是为了防止高度值刚好为0时呈现黑色
            for(int i = 0;i < mTerrainTextureID.length;i++){
                //sources.get(i).setRegion(0 + t * i, t + t * i, t * 2 + t * i);
                GLES32.glUniform1i(GLES32.glGetUniformLocation(mShader.mShaderProgram, textures[i] + ".materail"), i);
                //为了防止有些地面网格高度为0时输出黑色,这里区域起始部分应该为-1 + t * i;
                GLES32.glUniform4f(GLES32.glGetUniformLocation(mShader.mShaderProgram, textures[i] + ".region"), offsetX + t * i, offsetX + t + t * i, offsetX + t * 2 + t * i, 1.0f / (t) * 1.0f);
            }
            GLES32.glUniform2f(GLES32.glGetUniformLocation(mShader.mShaderProgram, "hOffset"), mLocation[1], 0.0f);
            GLES32.glUseProgram(0);
        }
        GLES32.glUseProgram(mShader.mShaderProgram);
        GLES32.glUniformBlockBinding(mShader.mShaderProgram, GLES32.glGetUniformBlockIndex(mShader.mShaderProgram, "MATRIX"), 0x001);
        GLES32.glUseProgram(0);
    }
    private static class SourceTexture{
        //位图资源
        Bitmap mSource;
        //可见度
        float mVisibility;
        //管辖区域
        float mLow, mOptimal, mHigh;

        public SourceTexture(Bitmap source) {
            this.mSource = source;
        }
        public final void setRegion(float low, float optimal, float high){
            mLow = low;
            mOptimal = optimal;
            mHigh = high;
        }
        public final void showRegion(){
            GLLog.loge("[" + mLow + "---" + mOptimal + "---" + mHigh + "]");
        }

        public static class RGBA{
            int r, g, b, a;

            public RGBA(int r, int g, int b, int a) {
                this.r = r;
                this.g = g;
                this.b = b;
                this.a = a;
            }

            public static final int rgbToColor(int r, int g, int b){
                int color = 0;
                //color[i] = (red << 16) | (green << 8) | blue | 0xFF000000;
                color = (r << 16) | (g << 8) | b | 0xFF000000;
                return color;
            }
            @RequiresApi(api = Build.VERSION_CODES.O)
            public static final Color rgbToColor2(int r, int g, int b){
                return Color.valueOf(r, g, b, 0xFF000000);
            }
        }

        /**
         * 计算可见度
         * @param h
         */
        public final void scaleVisibility(float h, float max_h){
            if(h <= mLow || h >= mHigh){
                mVisibility = 0.0f;
                return;
            }
            if(h == mOptimal){
                mVisibility = 1.0f;
            }
            else if(h > mOptimal){
                mVisibility = (mHigh - h) * 1.0f / (mHigh - mOptimal);
            }
            else{
                mVisibility = (h - mLow) * 1.0f / (mHigh - mOptimal);
            }
        }
        /**
         * 根据可见度采样像素值
         * @param x
         * @param y
         * @return
         */
        public final RGBA sampler(int x, int y){
            int color = mSource.getPixel(x % mSource.getWidth(), y % mSource.getHeight());
            int r = Color.red(color);
            int g = Color.green(color);
            int b = Color.blue(color);
            return new RGBA((int)(r * mVisibility), (int)(g * mVisibility), (int)(b * mVisibility), 255);
        }
    }
    /**
     * 根据指定高度信息生成地形纹理
     * @param hmap
     */
    public final Bitmap markTexture(int[] hmap){
        int width = mTerrainWidth + 1;
        int height = mTerrainHeight + 1;
        //加载4张原材料(可以不止4张)
        //黄图、草地、岩石、雪地
        SourceTexture loess, grassland, rock, snow;
        loess = new SourceTexture(FileUtils.getFromAssetsAtBitmap("textures/loess.png"));
        grassland = new SourceTexture(FileUtils.getFromAssetsAtBitmap("textures/grassland.png"));
        rock = new SourceTexture(FileUtils.getFromAssetsAtBitmap("textures/rock.png"));
        snow = new SourceTexture(FileUtils.getFromAssetsAtBitmap("textures/snow.png"));
        List<SourceTexture> sources = new ArrayList<>();
        sources.add(loess);
        sources.add(grassland);
        sources.add(rock);
        sources.add(snow);
        //计算管辖区域(除以原材料)
        int t = (int) (mMax_Height * 1.0f / (sources.size() + 1));
        float offset = 0.0f;
        for(int i = 0;i < sources.size();i++){
            sources.get(i).setRegion(offset + t * i, offset + t + t * i, offset + t * 2 + t * i);
        }
        //生成纹理
        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        int r, g, b;
        SourceTexture.RGBA rgba;
        for(int z = 0;z < height;z++){
            for(int x = 0;x < width;x++){
                int h = hmap[x + z * width];
                //计算h在原料中管辖区域可见度
                for(int i = 0;i < sources.size();i++){
                    if(i == 0 && h < sources.get(i).mOptimal){
                        sources.get(i).scaleVisibility(sources.get(i).mOptimal, mMax_Height);
                    }
                    else if(i == sources.size() - 1 && h > sources.get(i).mOptimal){
                        sources.get(i).scaleVisibility(sources.get(i).mOptimal, mMax_Height);
                    }
                    else{
                        sources.get(i).scaleVisibility(h, mMax_Height);
                    }
                }
                //计算合成颜色
                r = g = b = 0;
                for(int i = 0;i < sources.size();i++){
                    rgba = sources.get(i).sampler(x, z);
                    r += rgba.r;
                    g += rgba.g;
                    b += rgba.b;
                }
                r = Math.min(Math.max(0, r), 255);
                g = Math.min(Math.max(0, g), 255);
                b = Math.min(Math.max(0, b), 255);
                result.setPixel(x, z, SourceTexture.RGBA.rgbToColor(r, g, b));
            }
        }
        for(int i = 0;i < sources.size();i++){
            sources.get(i).mSource.recycle();
        }
        result = BitmapTools.rotaingImageView(-90, result);
        return result;
    }
    QuadTreeAtTerrain quadTreeAtTerrain;
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public Terrain(String name) {
        super(name);
        mTextureMapMode = S_TEXTURE_MODE_STATIC;
        markTerrain();
        quadTreeAtTerrain = new QuadTreeAtTerrain();
        quadTreeAtTerrain.markQuadTree(this);
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void render(float exTime) {
        super.render(exTime);
        GLES32.glUseProgram(mShader.mShaderProgram);
        for(int i = 0;i < mTerrainTextureID.length;i++){
            GLES32.glActiveTexture(GLES32.GL_TEXTURE0 + i);
            GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, mTerrainTextureID[i]);
        }
        GLES32.glEnable(GLES32.GL_CULL_FACE);
//        GLES32.glBindVertexArray(mTerrainVAO[0]);
//        GLES32.glDrawElements(GLES32.GL_TRIANGLES, mIndexSize, GLES32.GL_UNSIGNED_INT, 0);
//        GLES32.glBindVertexArray(0);
        quadTreeAtTerrain.render();
        GLES32.glDisable(GLES32.GL_CULL_FACE);
        for(int i = 0;i < mTerrainTextureID.length;i++){
            GLES32.glActiveTexture(GLES32.GL_TEXTURE0 + i);
            GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, 0);
        }
        GLES32.glUseProgram(0);
//        //线框
//        GLES32.glUseProgram(mLineShader.mShaderProgram);
//        GLES32.glBindVertexArray(mLineVAO[0]);
//        GLES32.glDrawElements(GLES32.GL_LINES, mLineIndexCount, GLES32.GL_UNSIGNED_INT, 0);
//        GLES32.glBindVertexArray(0);
//        GLES32.glUseProgram(0);
    }

    /**
     * 获取(x,z)位置高度
     * 根据平面方程-点法式:
     * n为平面的法向量，n=(A,B,C),M,M'为平面上任意两点，则有n·MM'=0, MM'=(x-x0,y-y0,z-z0)，
     从而得平面的点法式方程：A(x-x0)+B(y-y0)+C(z-z0)=0
     * @param x
     * @param z
     * @return
     */
    public final float getTerrainHeight(float x, float z){
        return quadTreeAtTerrain.lookAtTriangle(x, z);
    }

    /**
     * 获取地形高度
     * @param x
     * @param z
     * @return
     */
    public final float getTerrainHeightFast(float x, float z){
        //还原为原坐标值(即网格边长为1时)
        x *= mRectLengthSqrt;
        z *= mRectLengthSqrt;
        float h=0;
        float Xb,Yb;
        int Xa,Ya;
        Xa=(int)x;
        Ya=(int)z;
        Xb=x-Xa;
        Yb=z-Ya;
        //由于terrainArray[][]对高度图的读取是相反x,z的,所以取值时是[Y][X]格式
        float a = terrainArray[Ya][Xa].y;
        float b = terrainArray[Ya][Xa + 1].y;
        float c = terrainArray[Ya+1][Xa].y;
        float d = terrainArray[Ya+1][Xa+1].y;
        h=(a*(1-Xb)+b*Xb)*(1-Yb)+(c*(1-Xb)+d*Xb)*Yb;
        return h;
    }
    @Override
    public void update(float exTime) {
        super.update(exTime);
        quadTreeAtTerrain.update(GLGraphics.getCamera().eye.vec[0], GLGraphics.getCamera().eye.vec[2]);
    }
}
